/*
 * go.js
 * http://dev.akinao.com/
 */
//@require name.js,lang.js,game/board.js
akinao.namespace('game.go');
(function(){

	// Short cut name
	var Point = akinao.game.Point;
	var PointMap = akinao.game.PointMap;
	var Board = akinao.game.Board;
	var Lang = akinao.lang;

	var EMPTY = 0;
	var BLACK = 1;
	var WHITE = 2;

	function Go(handicap) {
		this.clear(handicap);
	}

	function checkAround(board, point) {
		var checkedBoard = new PointMap();
		// get player
		var me = board.get(point);
		var existOther = false;
		var searchPointStock = [point];
		var stockIndex = 0;
		checkedBoard.set(true, point);
		while (searchPointStock.length > stockIndex) {
			var checkCenterPoint = searchPointStock[stockIndex];
			// check up, right, down, left from center point.
			for (var i in Point.DIR4) {
				var checkPoint = checkCenterPoint.add(Point.DIR4[i]);
				if (board.isOut(checkPoint)) {
					continue;
				}
				// find empty
				var value = board.get(checkPoint);
				if (EMPTY == value) {
					return [];
				} else if (me == value) {
					if (Lang.isUndefined(checkedBoard.get(checkPoint))) {
						searchPointStock.push(checkPoint);
						checkedBoard.set(true, checkPoint);
					}
				} else {
					existOther = true;
				}
			}
			stockIndex++;
		}
		return existOther ? searchPointStock : [];
	}

	Go.prototype.set = function(player, point) {
		if (this.board.isOut(point)) {
			return {error: "OutOfBoard"};
		}
		if (EMPTY != this.board.get(point)) {
			return {error: "NotEmpty"};
		}
		this.board.set(player, point);
		var another = Go.anotherPlayer(player);
		var dead = (0 < checkAround(this.board, point).length);
		var removes = [];
		for (var i in Point.DIR4) {
			var checkPoint = point.add(Point.DIR4[i]);
			if (this.board.isOut(checkPoint)) {
				continue;
			}
			if (another == this.board.get(checkPoint)) {
				var captures = checkAround(this.board, checkPoint);
				if (0 < captures.length) {
					for (var j in captures) {
						var capture = captures[j];
						removes.push(capture);
						this.board.set(EMPTY, capture);
					}
					dead = false;
				}
			}
		}
		if (dead) {
			this.board.set(EMPTY, point);
			return {error: "Dead"};
		}
/*
		//コウダテのチェック
		if (count_ > 0 && tn.size() == 2) {
			Vector lt = (Vector) turn_.elementAt(count_ - 1);
			if (lt != null && lt.size() == 2) {
				if (((Point) lt.elementAt(0)).equals((Point) tn.elementAt(1)) && ((Point) lt.elementAt(1)).equals((Point) tn.elementAt(0))) {
					//置いた石を取る
					board_.set(pt, EMPTY);
					//置いた石を取る
					board_.set((Point) tn.elementAt(1), another);
					return Go.ERROR_NOT_KODATE;
				}
			}
		}
		while (turnCount_ > count_) {
			turn_.removeElementAt(turnCount_ - 1);
			turnCount_--;
		}

		turn_.addElement(tn);

		//手数をカウントアップ
		count_++;
		turnCount_ = count_;
*/
		var turns = [];
		var values = [];
		turns.push({set: true, player: player, point: point});
		values.push({set: true, player: player, point: point});
		for (var i in removes) {
			turns.push({set: false, player: another, point: removes[i]});
			values.push({set: false, player: another, point: removes[i]});
		}
		this.turnCount++;
		this.hamaCount[player] += removes.length;
		this.turns.push(turns);
		return {values: values};
	}

	Go.prototype.previous = function() {
		if (0 == this.turns.length) {
			return {error: "First"};
		}
		this.turnCount--;
		var values = [];
		var turns = this.turns.pop();
		for (var i in turns) {
			var value = turns[i];
			if (false == value.set) {
				this.hamaCount[Go.anotherPlayer(value.player)]--;
			}
			this.board.set(value.set ? EMPTY : value.player, value.point);
			values.push({set: !value.set, player: value.player, point: value.point});
		}
		return {values: values};
	}

	Go.prototype.get = function(point) {
		return this.board.get(point);
	}

	Go.prototype.lastTurn = function() {
		if (0 == this.turns.length) {
			return {};
		}
		var turn = this.turns[this.turns.length - 1];
		return this.turns[this.turns.length - 1][0];
	}

	Go.prototype.getAll = function() {
		var values = [];
		for (var x = 0; x < this.board.size.x; x++) {
			for (var y = 0; y < this.board.size.y; y++) {
				var point = new Point(x, y);
				var player = this.get(point);
				if (Go.EMPTY != player) {
					values.push({set: true, player: player, point: point});
				}
			}
		}
		return {values: values};
	}

	Go.prototype.clear = function(handicap) {
		this.board = new Board(19, EMPTY);
		this.turnCount = 0;
		this.hamaCount = [];
		this.hamaCount[BLACK] = 0;
		this.hamaCount[WHITE] = 0;
		this.turns = [];
		setHandicap(handicap, this.board);
	}

	Go.prototype.size = function() {
		return this.board.size;
	}

	Go.prototype.count = function() {
		return this.sgf.count();
	}

	Go.anotherPlayer = function(player) {
		return 3 - player;
	}

	function setHandicap(number, board) {
		if (Lang.isUndefined(number)) {
			return {};
		}
		var points = [];
		if (2 > number || 9 < number) {
			return {};
		}
		if (2 <= number) {
			points.push(new Point(15, 3));
			points.push(new Point(3, 15));
		}
		if (3 <= number) {
			points.push(new Point(15, 15));
		}
		if (4 <= number) {
			points.push(new Point(3, 3));
		}
		if (5 == number || 7 == number || 9 == number) {
			points.push(new Point(9, 9));
		}
		if (6 <= number) {
			points.push(new Point(3, 9));
			points.push(new Point(15, 9));
		}
		if (8 <= number) {
			points.push(new Point(9, 3));
			points.push(new Point(9, 15));
		}
		for (var i in points) {
			var point = points[i];
			board.set(BLACK, point);
		}
	}

	Go.EMPTY = EMPTY;
	Go.BLACK = BLACK;
	Go.WHITE = WHITE;

	akinao.game.go.Go = Go;
})();
